版本管理工具 - GitHub

版本管理工具的作用


1. 备份文件

就像我们使用U盘网盘备份电影、文档一样,写代码的时候也需要有个东西帮我们备份,每当代码有修改的时候,提交我们的修改给版本管理工具进行保管,万一电脑坏了还能从备份里恢复回来,其实备份是我们项目管理中最基本的一个事情,因为每天的工作结果都保存在这个文件当中,如果某天因为一些不可预料的因素导致文件丢失,就像玩游戏时打 BOSS ,如果不提前存档,那么打输了,之前的游戏记录就全消失了,还得重新打。


2. 记录历史

版本管理工具会帮助我们保管文件,但是版本管理工具的保管和网盘,U盘的保管不尽相同,网盘和U盘帮我们保存的是一个最新的文件状态,而历史的版本是找不回来的,比如说网盘里有一个文件,是用来记录每天的日记,有一天我们想知道某一天的某一行是哪天,几点钟加上去的,这个信息网盘或者U盘是没有办法告诉我们的,除非我们自己在这个地方加一条改动记录。

而版本管理工具是在我们每一次修改完,提交给版本管理工具后,它都会留一份备份,它会记录着当时这个修改是几点几分,是谁进行的修改,那么这样的话,当我们需要去回溯,去查找这些信息的时候,版本管理工具是可以告诉我们的。


3. 回到过去

版本管理工具会将我们每一次的修改做一个备份,如果我们不小心删除了某一个日记,并将这个删除也提交给了版本管理工具,通过版本管理工具,我们是可以通过历史备份把它恢复过来的,就好像是一个机器猫的时光机,我们可以让我们的文件恢复到任意过去的一个时间的的状态。


4. 多端共享

版本管理工具的另一个特性是我们托管的文件可以在多端进行同步,类似于苹果的 iCould 服务,我们可以在不同的设备上拿到最新的文件。比如说某天我在公司的电脑上提交了一个文件,可能是我们正在进行的一个工作,而我们没有做完就提交到了版本管理工具。那么我们可以回到家之后,通过版本管理工具,把我们之前提交的做到一半的的文件拿回来继续写,这就是多端共享。


5. 团队协作

软件开发项目和复仇者联盟团伙作案其实很相似,在我们的团队中,虽然各个都可以独挡一面,但是如果配合不好的话,也会相互扯后腿。版本管理工具就是帮我们解决这种冲突的,即使我们发生了一些冲突,版本管理工具也可以帮我们迅速的解决我们的一些冲突,将负面影响降低到最小。


版本管理工具区别

版本管理工具分为两种,集中式和分布式,集中式的版本管理工具代表如 CVSSVN ,是比较老的版本工具,分布式的如 GitGitHub ,是新型的版本管理工具。

所谓集中式,就是说它必须要有一个中心服务器来放置最新的文件,如果不联网就没有办法提交和查看。

而分布式的版本管理工具,每一个拥有版本库的人都可以在不联网的情况下快速完成文件的提交、查看记录、删除等操作,在效率上比集中式要高很多。

其中 GitGitHub 经常出现在一起,导致很多人认为它们是一个东西,其实不然,GitHub 实际上是一个程序员社区网站,在这个网站上程序员可以托管他自己的代码库,当然托管这件事是基于 Git 完成的。

GitHub客户端下载和使用

点击进入 GitHub桌面版 下载对应的版本,以 Mac 为例,将 GitHub 拖进 Applications ,打开后点击Continue ,输入 GitHub 的用户名和密码 。

往客户端里面添加项目仓库有三种方式。点击上图箭头所指的 + 号,就可以看到了,也就是下面图中的AddCreateClone 这三种形式。

add :来源是你本地机器上已经存在的项目,填写它的文件夹位置,然后点击 Create&Add Repository,如果这个项目本身就是一个 Git仓库 了,就直接添加进来,如果不是,就把它变成一个 Git仓库其实也就是在项目内创建一个 .git 文件夹)然后再添加进客户端。

add


create :就是自己新建项目。填写项目名,选择项目存放位置,然后点 Create Repository 按钮,仓库就创建好了。

create


clone:就是从 GitHub.com 上往本地 clone 。选中一个项目,在本地硬盘上找一个位置存放起来就可以了。

create

Clone的工作原理


项目修改

在你对项目中的文件进行修改后,要特别留意以下几点:

1
2
3
4
5
6
7
8
9
1. 项目修改数量的提醒;
2. 文件修改数量的提醒;
3. 是否只需要修改部分内容,蓝色标识代表将要修改;
4. 你对此次修改的留言;
5. 你对此次修改的详细描述;


删除项目

要删除一个仓库,就到下图左侧列表的项目名字上,右击,然后点 Remove 就行了。简单说说另外几项,AtomGitHub 公司开发的开源免费的代码编辑器,Terminal 是命令行终端,Finder 是文件浏览器。


查看修改历史

进入 History ,红框内依次是修改留言、修改人、上个版本号、修改时间。


撤销最近一次的修改

值得注意的是 Undo 适用于未同步到 GitHub 之前的操作,如果已经进行过同步,需要进入 History ,点击Revert This Commit 进行撤销:


发布项目到 GitHub


同步项目到GitHub

当项目发布以后,Publish 就会变成 Sync 了,以后这个项目的下的文件改变以后,可以点击 Sync 同步到 GitHub

Sync 的工作原理


GitHub 分支

Git 最核心的操作对象是版本( commit ) ,版本最核心的操作技巧就是分支(branch)

仓库创建后,一旦有了新 commit ,默认就会放到一个分支上,名字叫 master 。前面看到的多个版本组成的一条历史线,就是 master 分支。但是一个仓库内,用户可以自己创建其他的分支,可以有多条历史线。

master 这个名字,一般中文叫【主分支】,其实从技术底层来讲它跟其他我们自己要创建的分支没有区别,只不过它是天生的默认分支。实际工程项目中会人为的给它一个重要的使命,存放稳定代码。就像 GitHub 公司倡导的。

master 分支上的所有代码都应该是可以部署的

意思就是 master 分支上的代码是随时可以放到产品服务器上跑的代码。这样,如果想开发一个新功能,可以新开分支。 想象一下历史线上有很多节,每个版本就是一节。一个分支相当于一跟竹子,一节节的往上长。

但是实际上在底层并不是每个分支都拷贝出自己独立的一条历史线。其实 master 本身只是一个指针,指向 master 分支上最新的一个版本。这样由于每个 commit 都可以顺藤摸瓜找到自己的前一个 commit,那么这条历史线就可以确定了。

master 的原理

img


创建新分支

点击所示按钮,就会弹出对话框。Create new branch 就是来创建一个分支。所谓 from master 意思是基于 master 分支,拥有和 master 一样的历史

Branch

分支的原理

就是就是创建一个新的指针,跟 master 指针指向同一个版本,根本没有拷贝历史线。

如果现在我们对项目做一下修改,然后 commit 了。那么移动的只是 idea 指针,master 不变。就成了这样:

img

现在 master 分支包含两个版本 C1 和 C2idea 分支包含三个版本 C1,C2,C3

默认情况下这个 idea 分支只是存在于本地,如果想在远端仓库上发布这个分支,就点一下 idea 分支右侧的Publish 按钮。现在这个项目就有了两个分支。

webGitHub


删除分支

删除分支不在图形界面中,在顶部的控制栏 Branch - Delete 。如果只删除 GitHub.com 的分支,而不删除本地的分支,使用 Branch - Unpublish


分支合并

分支合并在顶部的控制栏 Branch - Merge ,他会新成了一个 C5 ,这是一个 融合版本( Merge Commit ) ,这个合并比较特殊,里面一般没有修改内容,它的作用主要是把两个分支合并起来。怎么合并的呢?融合版本包含两个版本,一个指向 C2 ,一个指向 C3

master 分支指针指向了 merge commit ,也就自动拥有了 idea 分支上的 C3 这个版本了。idea 分支一般现在就可以删除了。

分支融合的工作原理

img


代码冲突

实际中经常有这样的情况,我们正在 idea 分支上开发一个功能。但是这个时候突然发现了一个紧急的问题需要修复,所以会直接到 master 分支上,做一个 commit 来解决这个紧急的问题。然后会来继续到 idea 上开发。

其他的情形也有,总之这样就会出现,两个不同分支上并行开发,同时都有新的 commit ,这个一般没有问题,一样可以直接 merge ,如下图:

img

但是如果在两个分支上改动了同一个地方,合并的就会出现代码冲突。 因为 Git 不知道该听哪个分支的,所以只能报出冲突的位置,让开发者手动解决。


合并远端分支

现在我们的本地仓库叫 TestRepositoryGitHub.com 上也托管了这个仓库。那么自然就有一个本地master 分支,和一个 远端master 分支 ,这两个分支虽然名字都叫 master ,但是本质上也是两个分支,也存在分支合并的问题。

举例来说,我们在 GitHub.com 网页上,修改一下项目,把修改内容 commitmaster 分支之上。这样,远端master 分支就比 本地master 分支多了一个 commit 。此时在我们的客户端点 sync 按钮执行同步,这个 commit 就会直接被 pull 到本地。

另外一种情况,在没有 sync 之前,我们在本地也做了一个 commit ,也就是 本地master远端master 出现了并行开发的情况,这种情况是非常常见的。这个时候我们执行 sync ,跟本地两个分支合并是一样的,一般也会生成一个 merge commit ,在本地客户端和 GitHub.com 上的历史线都可以看到。

在特定条件下,点击 sync 按钮两个分支合并会不使用 融合( merge ) 方式,而采用 变基( rebase ) 方式,这样最终不会生成一个 merge commit 。但是达成的效果是一样的,也是实现了两个分支代码的合并,处理冲突的方式也一样,所以暂时不必深究。

团队合作

前面讲的都是开发者唱独角戏,但是尽管如此也可以看出 Git 带来的便利了,比如代码写错了可以回滚,为了新功能开发可以开新分支等等。但是 Git 和 GitHub 更大的威力在于协作

GitHub 是 Git 仓库的托管平台,让我们的项目仓库可以方便的备份同步。但是其实也许比这个还要重要的是,GitHub 是一个大家一起协作做项目的平台,是一种开发者的工作方式,引导一种看着不像流程的一种真正健康轻便的开发流程。

Github 的核心叫做 Github Flow ,网站上的各个功能都是围绕着这个核心来开发的。GitHub Flow 就是一套团队协作流程,它是一个非常轻便的,基于分支的工作流。非常适合代码部署非常频繁的团队和项目。概况来讲,它就是给一个项目开发新功能要走的几步,整个过程的核心是“拉取请求” 。

1
2
3
4
5
6
7
8
9
1. 创建新的分支。
2. 不断实现功能,做成一个新版本。
3. 发起拉取请求 Pull Request ;
4. 代码审核;
5. 把分支的内容合并到 master ;

使用 GitHub Flow 进行代码开发分为两种情况,第一种是团队成员之间互相熟知,另外一种是在开源项目当中,与互不相识的开源贡献者合作。

下面我们用一个实际例子先来了解团队中的协作:

我要和 Team 合作开发一个新项目,于是我先创建这个项目,然后让 Team 具有写的权限,创建项目前面已经介绍过,下面我们让 Team 成为这个项目的协作者。

首先到项目页面,点击 Settings 一项,到项目的 Settings 页面,可以看到如下图所示的 Collaborator 选项,输入框中输入协作者的用户名,此时这个协作者就具有对这个项目的写权限了。

Collaborators

对于非常有把握的代码,可以直接在 本地master 开发然后 sync远端master 分支上面。但是如果是比较重要的功能,就需要走完整的 GitHub Flow 流程了。

整个 GitHub Flow 的核心就是 Pull Request ,而 Pull Request 的目的就是用来引发讨论和代码审核的


NO.1 我们来开一个新的分支,这是后面进行 Pull Request 的前提。

add-home-page


NO.2 现在 Team 登录以后,就会收到提醒,也就是我们所做的修改。

commit


NO.3 Team 可以进入这个分支的版本中,进入我们所做的修改,对它留言进行讨论。发布的讨论对方会收到通知和提醒。

talk


NO.4 当我和 Team 不断完善这个分支,并完成它时,就可以发起 Pull Request 了。

pullRequest


NO.5 这时就相当于告诉项目的发起者,可以将这个分支合并到 master

pullrequest2


NO.6 在大家都讨论完毕后,就可以将这个分支和 master 进行合并了:

pullRequest3


至此,团队协作进行一个项目就完成了。